/**
 * 
 */
package org.dragonfire.dasm.directives;

import java.util.ArrayList;

import org.dragonfire.dasm.Command;
import org.dragonfire.dasm.Listing;
import org.dragonfire.dasm.DirectiveManager.Directive;
import org.dragonfire.parser.Equation;
import org.dragonfire.util.DMath;
import org.dragonfire.util.DString;

/**
 * Inserts raw data into the output file. Each numerical argument passed is
 * truncated to a byte and inserted while each string argument is divided up
 * into individual chars, each of which is inserted as it's ascii value.<br />
 * <br />
 * Format:<br />
 * <code>#DB <i>&lt;arg1&gt;</i>[,<i>&lt;arg2&gt;</i>[,<i>...</i>]]</code><br />
 * <br />
 * Parameters:<br />
 * <table>
 * <tr>
 * <td><code>arg1</code></td>
 * <td> (Integer/String) The data to be placed into the output file. If an
 * integer is passed, then the integer is truncated to the first 8 bits and that
 * is used. If a string is passed, then each character in the string is
 * truncated to a byte and inserted. Because of the 1 byte / char limitation,
 * only ascii and extended ascii characters are supported by this directive.
 * Full unicode support can be found in the <code>#</code>{@link org.dragonfire.dasm.directives.Dw}
 * directive.</td>
 * </tr>
 * </table><br />
 * Errors:<br />
 * <i>None</i>
 * 
 * @see org.dragonfire.dasm.directives.Dw
 * @author Darth Android
 * @version 2.0
 */
public class Db extends Directive {

	@Override
	public void pass2(Listing lst, Command c) {
		// buffer to hold the data in
		ArrayList<java.lang.Byte> data = new ArrayList<java.lang.Byte>();
		// loop through params
		for (String s : c.getParams()) {
			s = eval(s);
			if (Equation.isString(s)) {
				// get the actual string that will be written into the output
				s = evalString(s);
				/*
				 * Add all characters to the output. Each character must be
				 * trimmed to fit, limiting it to the first 256 characters.
				 */
				for (char ch : s.toCharArray()) {
					data.add(DMath.trimBin((int) ch, 1)[0]);
				}
			}
			else
				data.add(DMath.trimBin((int) DMath.parseDouble(s), 1)[0]);
		}
		// update the output data
		lst.setMCode(data);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ArrayList<Listing> pass1(Command c) {
		// The total length, in bytes, that this #DB isntruction will use
		int length = 0;
		// loop through all params
		for (String s : c.getParams()) {
			s = eval(s);
			// check if it's a string
			if (Equation.isString(s)) {
				// get the actual string that will be written into the output
				s = DString.extractString(s);
				// add it's size
				length += s.length();
			}
			// bytes take up... one byte.
			else
				length++;
		}
		// lock in static values
		String paramsRaw = getCompiler().evalStatics(c.getRawParams());
		// create a listing
		ArrayList<Listing> list = new ArrayList<Listing>();
		Listing l = new Listing(length, c);
		list.add(l);
		return list;
	}
}
